﻿#pragma once
#ifndef _AS_REDIS_CONN_H_
#define _AS_REDIS_CONN_H_


#ifdef AS_REDIS
extern "C" {
#include <hiredis/hiredis.h>
}
#include <string>
#include <functional>
#include <memory>
#include <list>
#include <mutex>
#include <condition_variable>

#ifdef WIN32
#include <WinSock2.h>
#endif

namespace as
{
namespace db
{    
    enum
    {
        ECON_WAIT_TIME = 2,
    };
    struct RedisConf
    {
        RedisConf(const std::string &path);
        RedisConf(const std::string h, const std::string password, int p = 6379, timeval tv = {1, 500000});
        ~RedisConf() {}
        std::string host;
        std::string pw;
        int port = 0;
        timeval timeout;
    };

	class RedisResult;
    struct RedisTask
    {
        std::time_t start_tick = 0;
        std::time_t do_tick = 0;
        std::string command;
        std::function<void(RedisResult*)> cb;
    };

    class RedisClient
    {
    public:
        friend struct RedisControl;
        RedisClient(redisContext *con);
        RedisClient(const RedisConf &conf);
        ~RedisClient();
        bool Set(const std::string &keys, const std::string &val, const std::function<void(RedisResult*)> &fun);
        bool HashSet(const std::string &keys, const std::string &field, const std::string &val, const std::function<void(RedisResult*)> &fun);
        bool Get(const std::string &keys, const std::function<void(RedisResult*)> &fun);
        bool HashGet(const std::string &keys, const std::string &field, const std::function<void(RedisResult*)> &fun);
        bool HashGetAll(const std::string &keys, const std::function<void(RedisResult*)> &fun);

        void AsyncSet(const std::string &keys, const std::string &val, const std::function<void(RedisResult*)> &fun);
    public:
        static std::string MakeSetCommand(const std::string &keys, const std::string &val);
        static std::string MakeHSetCommand(const std::string &keys, const std::string &field, const std::string &val);
        static std::string MakeGetCommand(const std::string &keys);
        static std::string MakeHGetCommand(const std::string &keys, const std::string &field);
        static std::string MakeGetAllCommand(const std::string &keys);

    public:

        redisContext* GetContext();
        void Tick();
    protected:
        RedisTask *MakeTask(const std::string &command, const std::function<void(RedisResult*)> &fun);
        bool HandleTask();

        void DoTask();

        bool RedisCommand(const std::string &keys, const std::function<void(RedisResult *)> &fun);
    private:
        redisContext *context_ = nullptr;
        bool reconnect_ = false;
        std::mutex list_lock_;
        std::condition_variable list_co_;
        std::list<RedisTask *> async_task_;
    };
}
}





#endif
#endif